iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0

大家好,我是Karin。
因為鐵人賽挑戰也快告一段落了,所以想藉由實作一個簡單的東西來當作是這系列的一個小成果。
還不確定能不能成功完成,總之就先來試試看。


第二天:實現拖放功能
目標:讓使用者能夠互動,將圖片塊拖放至正確位置。
使用拖放API(Drag and Drop API):
學習如何使用HTML5的Drag and Drop API,讓每個圖片塊變得可拖動。你需要為每個div圖片塊添加draggable屬性。
設置拖動事件:
為圖片塊設置dragstart事件,記錄當前正在被拖動的圖片塊。
在目標位置設置dragover事件,允許其他圖片塊進行放置。
設置放置事件:
在drop事件中,完成圖片塊之間的交換。這意味著使用者拖動一塊圖片後,應該與目標位置的圖片塊互換位置。
測試與優化:
測試拖放功能,確保圖片塊能夠被正確拖動並互換位置。檢查是否有邏輯上的錯誤或可優化的地方。
方向: 這一天的主要工作是掌握拖放功能,讓遊戲開始有互動性。務必確保每個圖片塊能順利拖放並互換位置。


正文開始:

今天主要學習的是這個Drag and Drop API(拖放API)
這是一個用來控制物件可以拖動與放置的功能。
允許使用者在網頁中將物件進行拖動與放置,並自定義拖放後的事件。

操作流程:

  1. 首先為每個物件(此處為拼圖塊)設置 draggable 屬性,使該物件可以被拖動。
  2. 設置 dragstart 事件:當物件被拖動時會出現的效果。
  3. 設置 dragover 事件:當物件被拖動至指定區域上方時,會觸發的結果。
    預設情況下,無法將物件放置到另一個物件上。
    因此使用preventDefault()函數,用來取消此預設情況,使物件能被放置到另一個物件上。
  4. 設置 drop 事件:當物件被拖動至指定區域上方並鬆開鼠標後,執行的特定操作。

程式碼

  • 設置拼圖塊可拖動:
    tile.draggable = true; 使每個拼圖塊都可以被拖動。
  • 拖動事件:
    dragstart 事件會在使用者開始拖動拼圖塊時觸發,將被拖動的拼圖塊存到 draggedTile 變數中,以便在放置時使用。
  • 允許拖放目標放置:
    dragover 事件會在拼圖塊被拖到其他拼圖塊上方時觸發,通過 e.preventDefault() 允許其他拼圖塊成為有效的放置目標。
  • 放置事件:
    drop 事件會在使用者放下拼圖塊時觸發。
    檢查被拖動的拼圖塊與目標拼圖塊是否不同,如果不同,就交換它們的 backgroundPosition,即交換顯示的圖片部分。

Javascript

document.addEventListener('DOMContentLoaded', function() {
  const imageUpload = document.getElementById('imageUpload');
  const puzzleContainer = document.getElementById('puzzle-container');
  let draggedTile = null; // 用來儲存當前被拖動的拼圖塊

  imageUpload.addEventListener('change', function(event) {
    const file = event.target.files[0]; // 取得上傳的圖片檔案
    if (file) {
      const reader = new FileReader();

      reader.onload = function(e) {
        const img = new Image();
        img.src = e.target.result;

        img.onload = function() {
          const rows = 3; // 固定為3行
          const cols = 3; // 固定為3列
          const containerWidth = puzzleContainer.clientWidth; // 取得容器寬度
          const containerHeight = puzzleContainer.clientHeight; // 取得容器高度

          // 根據容器大小計算每塊拼圖的寬高
          const tileWidth = containerWidth / cols;
          const tileHeight = containerHeight / rows;

          // 清除之前的拼圖
          puzzleContainer.innerHTML = '';

          // 設置拼圖容器的行列數
          puzzleContainer.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
          puzzleContainer.style.gridTemplateRows = `repeat(${rows}, 1fr)`;

          // 儲存圖片位置(背景位置)的資料
          const positions = [];

          for (let i = 0; i < rows * cols; i++) {
            positions.push({
              backgroundPosition: `${-(i % cols) * tileWidth}px ${-Math.floor(i / cols) * tileHeight}px`
            });
          }

          // 隨機打亂圖片的位置
          positions.sort(() => Math.random() - 0.5);

          // 根據打亂後的順序生成拼圖塊
          for (let i = 0; i < rows * cols; i++) {
            const tile = document.createElement('div');
            tile.classList.add('puzzle-tile');
            tile.style.width = `${tileWidth}px`;
            tile.style.height = `${tileHeight}px`;
            tile.style.backgroundImage = `url(${img.src})`;
            tile.style.backgroundSize = `${containerWidth}px ${containerHeight}px`;
            tile.style.backgroundPosition = positions[i].backgroundPosition;
            tile.draggable = true; // 設置拼圖塊為可拖動狀態

            // 設置拖動事件
            tile.addEventListener('dragstart', function() {
              draggedTile = tile; // 記錄當前被拖動的拼圖塊
            });

            // 設置拖放事件
            tile.addEventListener('dragover', function(e) {
              e.preventDefault(); // 允許放置
            });

            tile.addEventListener('drop', function() {
              if (draggedTile !== tile) {
                // 交換被拖動拼圖塊與目標拼圖塊的背景位置
                const draggedBackgroundPosition = draggedTile.style.backgroundPosition;
                draggedTile.style.backgroundPosition = tile.style.backgroundPosition;
                tile.style.backgroundPosition = draggedBackgroundPosition;
              }
            });

            // 添加拼圖塊到容器
            puzzleContainer.appendChild(tile);
          }
        };
      };

      reader.readAsDataURL(file);
    }
  });
});

今日結果:
拼圖塊可以拖動並交換位置了。
https://ithelp.ithome.com.tw/upload/images/20240928/20168967o2XGoijG2Y.png

今天嘗試了chatGPT的語音交談功能,打開新世界。


上一篇
Day 27 實作練習-拼圖小遊戲
下一篇
Day 29 實作練習-拼圖小遊戲-3
系列文
每天都進步一點!從零開始的JavaScript 與基礎網路知識學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言